package cn.sofwin.core.rbac.interceptor;

import cn.sofwin.core.rbac.annotation.HasLogin;
import cn.sofwin.core.rbac.annotation.HasPermission;
import cn.sofwin.core.rbac.annotation.HasRole;
import cn.sofwin.core.rbac.bean.LoginUser;
import cn.sofwin.core.rbac.service.AuthService;
import cn.sofwin.core.utils.api.StatusCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;

/**
 * 权限拦截器
 */
@Component
public class RbacInterceptor implements HandlerInterceptor {

    /**
     * 严格模式，开启此模式后，将会默认进行登录校验
     */
    @Value("${app.rbac.strict:true}")
    boolean strict;

    @Autowired
    AuthService authService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        LoginUser user = authService.getLoginUser(request);
        StatusCode status = null;
        if(handler instanceof HandlerMethod){
            HandlerMethod hm = (HandlerMethod) handler;
            HasLogin hasLogin = hm.getMethodAnnotation(HasLogin.class);
            HasRole hasRole = hm.getMethodAnnotation(HasRole.class);
            HasPermission hasPermission = hm.getMethodAnnotation(HasPermission.class);

            if((strict || hasLogin != null) && user == null){
                status = StatusCode.NoLogin;
            }

            boolean pass = true;
            if(status == null && hasRole != null){
                List<String> userRoles = user.roles();
                String[] roles = hasRole.value();
                for(String role : roles){
                    if(!userRoles.contains(role)){
                        pass = false;
                        break;
                    }
                }
                if(!pass){
                    status = StatusCode.NoRole;
                }
            }

            if(status == null && hasPermission != null){
                List<String> userPermissions = user.permissions();
                String[] permissions = hasPermission.value();

                pass = true;
                for(String permission : permissions){
                    if(!userPermissions.contains(permission)){
                        pass = false;
                        break;
                    }
                }
                if(!pass){
                    status = StatusCode.NoPermission;
                }
            }

        }

        if(status != null){
            authService.writeError(response, 403, StatusCode.NoPermission);
            return false;
        }else{
            return true;
        }
    }
}
